package gui.mainWindow;

import gui.ColorCustomizingWindow;
import gui.addArcherWindow.AddArcherWindow;
import gui.archerDbEditor.ArcherDbEditor;
import gui.fileImportWindow.FileImportWindow;
import gui.newTournamentWindow.NewTournamentWindow;
import gui.tournamentOptions.TournamentOptions;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Observable;
import java.util.Observer;

import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.SAXException;

import table.models.ParticipantsTableModel;
import table.models.StatisticsTableModel;
import tournamentData.TournamentData;
import core.ConstantRegexes;
import core.Constants;
import core.Person;
import core.XMLWriter;
import dataBase.DbHolder;

public class MainWindowController implements Observer {
	private final MainWindow window;

	public MainWindowController(MainWindow window) {
		this.window = window;
		DbHolder.getInstance().getArcherData().addObserver(this);
		TournamentData.getInstance().addObserver(this);
	}

	/**
	 * opens an xml file and disposes the main window to display the content in
	 * a new one
	 */
	protected void openFile() {
		final JFileChooser chooser = new JFileChooser();
		final FileFilter filter = new FileNameExtensionFilter("xml Dateien", Constants.XML_FILEENDING);
		chooser.addChoosableFileFilter(filter);
		final int ret = chooser.showDialog(null, "Datei öffnen");

		if (ret == JFileChooser.APPROVE_OPTION) {
			final File fileToOpen = chooser.getSelectedFile();
			this.window.dispose();
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					MainWindow inst;
					inst = new MainWindow(fileToOpen);
					inst.setLocationRelativeTo(null);
					inst.setVisible(true);
				}
			});
		}
	}

	/**
	 * import player data from a given CSV file
	 */
	protected void importFromFile() {
		StringBuilder messageText = new StringBuilder();
		messageText.append("Erlaubtes Format der CSV-Datei:");
		messageText.append("\n");
		messageText.append("Name;Vorname;Nation;Bundesland;Bogenkategore;Altersklasse;Verein;Geschlecht;Lizenz;Landeswertung;Geburtsdatum");
		messageText.append("\n");
		messageText.append("Kein Bereich darf ausgelassen oder leer bleiben, mit Ausnahme des Geburtsdatums.");
		messageText.append("\n");
		messageText.append("Erlaubte Werte für die Spalte Geschlecht: " + ConstantRegexes.genderRegEx);
		messageText.append("\n");
		messageText.append("Erlaubte Werte für die Spalten Lizenz und Landeswertung: " + ConstantRegexes.booleanRegEx);

		JOptionPane.showMessageDialog(this.window, messageText.toString());

		final JFileChooser chooser = new JFileChooser();
		final FileFilter filter = new FileNameExtensionFilter("csv Dateien", Constants.CSV_FILEENDING);
		chooser.addChoosableFileFilter(filter);
		final int ret = chooser.showDialog(null, "Datei öffnen");

		if (ret == JFileChooser.APPROVE_OPTION) {
			/** make informationgui visible */
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					try {
						FileImportWindow inst = new FileImportWindow(chooser.getSelectedFile());
						inst.setVisible(true);
						inst.setLocationRelativeTo(null);
						inst.getController().start();

					} catch (FileNotFoundException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			});
		}
	}

	public void buildNonParticipantsTable() throws SQLException {
		int notParticipatingPlayers = DbHolder.getInstance().getArcherData().getNumberOfEntries() - TournamentData.getInstance().getAllParticipants().length;

		if (notParticipatingPlayers > 0) {
			ParticipantsTableModel nonParticipantsTableModel = (ParticipantsTableModel) this.window.getNonParticipantsTable().getModel();
			nonParticipantsTableModel.removeData();
			Person [] allArchers = DbHolder.getInstance().getArcherData().getAllArchersInDBQuick();
			for (int i = 0; i < allArchers.length; i++) {
				if (allArchers [i] != null) {
					if (!TournamentData.getInstance().isParticipating(i)) {
						nonParticipantsTableModel.addRow(allArchers [i].toArrayPlusID(i));
					}
				}
			}
			nonParticipantsTableModel.fireTableDataChanged();
		}
	}

	public void buildParticipantsTable() throws SQLException {
		if (TournamentData.getInstance().getAllParticipants().length > 0) {
			ParticipantsTableModel participantsTableModel = (ParticipantsTableModel) this.window.getParticipantsTable().getModel();
			participantsTableModel.removeData();
			Integer [] participants = TournamentData.getInstance().getAllParticipants();
			for (int i = 0; i < participants.length; i++) {
				participantsTableModel.addRow(DbHolder.getInstance().getArcherData().getByIdToArray(participants [i]));
			}
			participantsTableModel.fireTableDataChanged();
		}
	}

	public void closeOperation() {
		DbHolder.getInstance().shutDown();
		this.window.dispose();
	}

	public void openDbEditor() {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				ArcherDbEditor.getInstance().setLocationRelativeTo(null);
				ArcherDbEditor.getInstance().setVisible(true);
			}
		});
		try {
			ArcherDbEditor.getInstance().getController().buildTable();
			ArcherDbEditor.getInstance().getController().setDropDownMenus();
			ArcherDbEditor.getInstance().getDbView().setRowSelectionInterval(0, 0);
			ArcherDbEditor.getInstance().getController().setDropDownMenus();
			ArcherDbEditor.getInstance().getController().filloutForm();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void openColorCustomization() {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				ColorCustomizingWindow.getInstance().setLocationRelativeTo(null);
				ColorCustomizingWindow.getInstance().setVisible(true);
			}
		});
	}

	public void createNewTournament() {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				NewTournamentWindow.getInstance().setLocationRelativeTo(null);
				NewTournamentWindow.getInstance().setVisible(true);
			}
		});
	}

	@Override
	public void update(Observable o, Object arg) {
		try {
			this.setShownTournamentInformation();
			this.setExtendedTournnamentInformation();
			this.buildNonParticipantsTable();
			this.buildParticipantsTable();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void setShownTournamentInformation() {
		this.window.getTournamentTypeDropDown().setSelectedItem(TournamentData.getInstance().getGeneralTournamentInformation().getTournamentType());
		this.window.getTournamentNameTextBox().setText(TournamentData.getInstance().getGeneralTournamentInformation().getTournamentName());
		this.window.getStartDateTextBox().setText(TournamentData.getInstance().getGeneralTournamentInformation().getStartDate().toString());
		this.window.getEndDateTextBox().setText(TournamentData.getInstance().getGeneralTournamentInformation().getEndDate().toString());
		this.window.getOrganizerTextBox().setText(TournamentData.getInstance().getGeneralTournamentInformation().getOrganizer());
		this.window.getTournamentLeadTextBox().setText(TournamentData.getInstance().getGeneralTournamentInformation().getTournamentLead());
		this.window.getRefereeTextBox().setText(TournamentData.getInstance().getGeneralTournamentInformation().getReferee());
	}

	public void setExtendedTournnamentInformation() throws SQLException {
		StatisticsTableModel model = (StatisticsTableModel) this.window.getStatisticsTable().getModel();
		model.removeData();

		/** players in database */
		int playersInDB = DbHolder.getInstance().getArcherData().getNumberOfEntries();
		model.addData("Spieler in Datenbank gesamt: ", playersInDB);

		/** participating players */
		int participatingPlayers = TournamentData.getInstance().getAllParticipants().length;
		model.addData("Turnierteilnehmer:", participatingPlayers);

		/** licensed players */
		int licensedPlayers = 0;
		for (int i = 0; i < TournamentData.getInstance().getAllParticipants().length; i++) {
			if (DbHolder.getInstance().getArcherData().getById(TournamentData.getInstance().getAllParticipants() [i]).isLicense()) {
				licensedPlayers++;
			}
		}
		model.addData("Davon mit Lizenz: ", licensedPlayers);

		/** bowCathegories */
		HashMap < String, Integer > bowCathegories = new HashMap < String, Integer >();
		for (int i = 0; i < TournamentData.getInstance().getAllParticipants().length; i++) {
			String bowCathegory = DbHolder.getInstance().getArcherData().getById(TournamentData.getInstance().getAllParticipants() [i]).getBowCathegory();
			if (bowCathegories.containsKey(bowCathegory)) {
				int value = bowCathegories.get(bowCathegory);
				bowCathegories.put(bowCathegory, value + 1);
			} else {
				bowCathegories.put(bowCathegory, 1);
			}
		}
		Iterator < Entry < String, Integer >> iterator = bowCathegories.entrySet().iterator();
		while (iterator.hasNext()) {
			Entry < String, Integer > entry = iterator.next();
			model.addData(entry.getKey() + ": ", entry.getValue());
		}
		model.fireTableDataChanged();
	}

	public void addArcher() {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				AddArcherWindow.getInstance().setLocationRelativeTo(null);
				AddArcherWindow.getInstance().setVisible(true);
				AddArcherWindow.getInstance().getController().setDropDownMenus();
			}
		});
	}

	public void setGeneralTournamentInformation() {
		try {
			XMLWriter.readFromFile(this.window.getFile());
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void openDistancesEditorWindow() {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				TournamentOptions.getInstance().setLocationRelativeTo(null);
				TournamentOptions.getInstance().setVisible(true);
				try {
					TournamentOptions.getInstance().getController().initializeDropDowns();
					TournamentOptions.getInstance().getController().updateTable();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
	}

	public void saveTournamentData() {
		try {
			XMLWriter.writeToFile(new File(XMLWriter.getFileName(TournamentData.getInstance().getGeneralTournamentInformation().getTournamentName(), TournamentData.getInstance()
					.getGeneralTournamentInformation().getStartDate())));
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
